package Parser;

import java.io.*;
import java.util.Vector;

/**
 * Title: KBParser
 * Description: Parses knowlegde bases
 * @version 1.0
 */

public class KBParser
{

  private String KBFile, KBError, KBContent;
  private boolean KBUniverse = false, KBVariable = false, KBRule = false, KBIf = false, KBThen = false;
  private Vector vecUniverses = new Vector();
  private Vector vecVariables= new Vector();
  private Vector vecRules = new Vector();

  public KBParser(String KBFileName)
  {
    this.KBFile = KBFileName;

    if(this.Parse() == true)
    {
      System.out.println(this.vecUniverses.size()+" Universes have been extracted from the knowledge base.");
      System.out.println(this.vecVariables.size()+" Variables have been extracted from the knowledge base.");
      System.out.println(this.vecRules.size()+" Rules have been extracted from the knowledge base.");
      //printenOpScherm();
    }
    else
    {
      System.out.println(KBError);
    }
  }

  public static void main(String Args[])
  {
    new KBParser("..\\KB_Test.txt");
  }

  private boolean Parse()
  {
    this.KBContent = this.RetreiveContent();

    if(this.KBContent == null)
    {
      //Return false access geterror for errortext
      return false;
    }
    else
    {
      this.SetUniverses();
      this.SetVariables();
      this.SetRules();
      return true;
    }
  }

  private String RetreiveContent()
  {
    //Read the file and set error if error occurs
    String KBtext = new String();

    try
    {
      BufferedReader reader = new BufferedReader(new FileReader(this.KBFile));

      try
      {
        while (reader.ready())
        {
          KBtext = KBtext + reader.readLine() + "\n";
        }
      } catch(FileNotFoundException e)
      {
        this.KBError = "Can not find file.\n";
        KBtext = null;
      }

      reader.close();
    } catch (IOException e)
    {
      this.KBError = "Error opening file\n";
      KBtext = null;
    }

    return KBtext;
  }

  private void SetUniverses()
  {
    int UBegin = 0, UEnd = 0;
    String CurrentUniverse;
    Universe tmpUniverse;

    //first universe
    try
    {
      UBegin = this.KBContent.indexOf("UNIVERSE") + 9;
      this.KBUniverse = true;
    } catch(Exception e)
    {
      this.KBError = "No universes defined";
      return;
    }

    if(this.KBUniverse == true)
    {
      try {
        UEnd = this.KBContent.indexOf("UNIVERSE_END");
        this.KBUniverse = false;
      }
      catch (Exception e)
      {
        this.KBError = "No end of universe defined";
        return;
      }
    }

    if (UBegin < 0 || UEnd < UBegin) return;
    CurrentUniverse = this.KBContent.substring(UBegin, UEnd);

    while (UEnd < this.KBContent.length())
    {
        //reading all the other universes
        try{
          UBegin = this.KBContent.indexOf("UNIVERSE",UEnd+12) + 9;
          this.KBUniverse = true;
        }
        catch (Exception e)
        {
          this.KBError = "No universes defined";
        }

        if (this.KBUniverse == true)
        {
          try {
            UEnd = this.KBContent.indexOf("UNIVERSE_END",UEnd+12);
            this.KBUniverse = false;
          }
          catch (Exception e)
          {
            this.KBError = "No end of universe defined";
          }
        }

        //universe aanmaken en toevoegen aan universe vector
        tmpUniverse = new Universe(CurrentUniverse.substring(0,CurrentUniverse.indexOf("\n")));
        vecUniverses.add(tmpUniverse);

        tmpUniverse.RetrieveSets(CurrentUniverse);

        if (UBegin < 0 || UEnd < UBegin) return;
        CurrentUniverse = this.KBContent.substring(UBegin, UEnd);
    }
  }

  private void SetVariables()
  {
    int UBegin = 0, UEnd = 0;
    String CurrentVariables, name, type, in;
    Variables tmpVariables;

    //first variable
    try
    {
      UBegin = this.KBContent.indexOf("VARIABLE") + 9;
      this.KBVariable = true;
    } catch(Exception e)
    {
      this.KBError = "No variables defined";
      return;
    }

    if(this.KBVariable == true)
    {
      try {
        UEnd = this.KBContent.indexOf("VARIABLE_END");
        this.KBVariable = false;
      } catch (Exception e)
      {
        this.KBError = "No end of variable defined";
        return;
      }
    }

    if (UBegin < 0 || UEnd < UBegin) return;
    CurrentVariables = this.KBContent.substring(UBegin, UEnd);

    while (UEnd < this.KBContent.length())
    {
        name = getWord(CurrentVariables, 0);
        type = getWord(CurrentVariables, 1);
        in = getWord(CurrentVariables, 2);

        //alleen geldig als het type overeenkomt met een bestaand universe
        if((this.universeExists(type) == true)&& !this.variableExists(name))
        {
          tmpVariables = new Variables(name, type, in);
          this.vecVariables.add(tmpVariables);
        } else {
          System.out.println("Variabele: " + name + " kan niet worden toegevoegd, type bestaat niet of naam wel!");
          System.exit(-1);
        }

        //reading all the other variables
        try
        {
          UBegin = this.KBContent.indexOf("VARIABLE",UEnd+12) + 9;
          this.KBVariable = true;
        } catch (Exception e)
        {
          this.KBError = "No variables defined";
        }

        if (this.KBVariable == true)
        {
          try {
            UEnd = this.KBContent.indexOf("VARIABLE_END",UEnd+12);
            this.KBVariable = false;
          } catch (Exception e) {
            this.KBError = "No end of variable defined";
          }
        }

        if (UBegin < 0 || UEnd < UBegin) return;
        CurrentVariables = this.KBContent.substring(UBegin, UEnd);
    }
  }

  private void SetRules()
  {
    int UBegin = 0, UEnd = 0, IFBegin = 0, IFEnd = 0, THENBegin = 0, THENEnd = 0;
    String CurrentRules;
    Rules tmpRules;

    //first variable
    try
    {
      UBegin = this.KBContent.indexOf("RULE") + 5;
      this.KBRule = true;
    } catch(Exception e)
    {
      this.KBError = "No rule defined";
      return;
    }

    if(this.KBRule == true)
    {
      try {
        UEnd = this.KBContent.indexOf("RULE_END");
        this.KBRule = false;
      } catch (Exception e) {
        this.KBError = "No end of rule defined";
        return;
      }
    }

    if (UBegin < 0 || UEnd < UBegin) return;
    CurrentRules = this.KBContent.substring(UBegin, UEnd);

    while (UEnd < this.KBContent.length())
    {
      try{
        IFBegin = this.KBContent.indexOf("IF", THENEnd) + 3;
        this.KBIf = true;
      } catch (Exception e) {
        this.KBError = "No if defined";
      }

      if (this.KBIf == true)
      {
        try {
          IFEnd = this.KBContent.indexOf("THEN", THENEnd);
          this.KBIf = false;
          this.KBThen = true;
        } catch (Exception e)
        {
          this.KBError = "No then defined";
        }
      }

      if (this.KBThen == true)
      {
        try {
          THENBegin = this.KBContent.indexOf("THEN", THENEnd) + 5;
          this.KBThen = false;
        } catch (Exception e)
        {
          this.KBError = "No then defined";
        }
      }

      //set end of rule for next if-then
      THENEnd = UEnd;

      //make object param name
      tmpRules = new Rules(this.getWord(KBContent.substring(UBegin, UEnd), 0));

      //add object to rules vector
      if(!this.ruleExists(tmpRules.GetName()))
      {
        //extract if statement
        tmpRules.setIf(this.getWord(KBContent.substring(IFBegin, IFEnd), 0), this.getWord(KBContent.substring(IFBegin, IFEnd), 2));
        tmpRules.checkANDOR(KBContent.substring(IFBegin, IFEnd));
        //extract then statement
        tmpRules.setThen(this.getWord(KBContent.substring(THENBegin, THENEnd), 0), this.getWord(KBContent.substring(THENBegin, THENEnd), 2));
        tmpRules.checkThenMore(KBContent.substring(THENBegin, THENEnd));

		//System.out.print(tmpRules.toString());
        this.vecRules.add(tmpRules);
      }

      //reading all the other rules
      if (this.KBRule == false)
      {
        try {
          UBegin = this.KBContent.indexOf("RULE", UEnd + 9) + 5;
          this.KBRule = true;
        }
        catch (Exception e)
        {
          this.KBError = "No rule defined";
        }
      }

      if (this.KBRule == true)
      {
        try {
          UEnd = this.KBContent.indexOf("RULE_END",UEnd+9);
          this.KBRule = false;
        } catch (Exception e)
        {
          this.KBError = "No end of rule defined";
        }
      }

      if (UBegin < 0 || UEnd < UBegin) return;
      CurrentRules = this.KBContent.substring(UBegin, UEnd);
    }
  }

  private boolean universeExists(String typename)
  {
    for(int i = 0; i<this.vecUniverses.size();i++)
    {
      if(((Universe)this.vecUniverses.get(i)).getName().equals(typename))
      {
        return true;
      }
    }
    return false;
  }

  private boolean variableExists(String varname)
  {
    for(int i = 0; i<this.vecVariables.size();i++)
    {
      if(((Variables)this.vecVariables.get(i)).getName().equals(varname))
      {
        return true;
      }
    }
    return false;
  }

  private boolean ruleExists(String rulname)
  {
    for(int i = 0; i<this.vecRules.size();i++)
    {
      if(((Rules)this.vecRules.get(i)).GetName().equals(rulname))
      {
        return true;
      }
    }
    return false;
  }

  private String getWord(String setstr, int nr)
  {
    int currentWord = 0;
    int i = 0;

    //remove starting and ending spaces etc..
    setstr = setstr.trim();

    while(setstr.length() > 0) {
      if(i == setstr.length() || setstr.charAt(i) == '\n' || setstr.charAt(i) == ' ' || setstr.charAt(i) == '\t') {
        //einde van huidige woord gevonden
        if(nr == currentWord) {  //huidige woord moet worden teruggegeven
          return (setstr.substring(0, i)).trim();
        }
        //nog niet het goede woord, doorgaan met volgende woord zoeken
        setstr = (setstr.substring(i, setstr.length())).trim();
        i=0;
        currentWord++;
      }
      i++;
    }
    return null;
  }

  public Vector GetUniverses()
  {
    return this.vecUniverses;
  }

  public Vector GetVariables()
  {
    return this.vecVariables;
  }

  public Vector GetRules()
  {
    return this.vecRules;
  }

  public String GetError()
  {
    return this.KBError;
  }

  public void printenOpScherm()
  {
  	String printje;
  	for(int a = 0; a < GetRules().size(); a++)
    {
    	printje = vecRules.elementAt(a).toString();
    	System.out.println(printje);
    }
  }

  public Universe getUniverse(String name)
  {
  	for(int f = 0; f < vecUniverses.size(); f++)
  	{
  		Universe tmpUni = (Universe) vecUniverses.elementAt(f);
  		if( tmpUni.getName().equals(name))
  		{
  			return (Universe) vecUniverses.elementAt(f);
  		}
  	}
  	Universe uni = null;
  	return uni;
  }
}
